Option Explicit
'
'
'  Creator:    $Creator: Paul_M_Thompson@Yahoo.com$
'  Script:     bat.DTCC_VerifyManifest_and_WorkingDir.vbs and DTCC_VerifyManifest_and_WorkingDir.vbs.vbs
'  Revision:   $Revision: 208 $
'  Date:       $Date: 2014-08-20 16:47:16 +0000 (Wed, 20 Aug 2014) $
'
'
'
' ----------------------------------------------------------------------------
'
CONST vbForReading = 1              ' Open a file for reading only. You can't write to this file.
CONST vbForWriting = 2              ' Open a file for writing.
CONST vbForAppending = 8            ' Open a file and write to the end of the file.
CONST vbTristateUseDefault = -2     ' Opens the file using the system default.
CONST vbTristateTrue = -1           ' Opens the file as Unicode.
CONST vbTristateFalse = 0           ' Opens the file as ASCII.
'
CONST PATHDELIM = "\"
' CONST WORKING_DIR    = "C:\Serena\ReleaseAutomationAgent\core\var\work\ABS_SQL"
CONST WORKING_DIR    = "C:\Users\Public\Documents\Virtual Machines\VmWareShare\Source\awk\DTCC"
' CONST MANIFEST_FNAME = "C:\Serena\ReleaseAutomationAgent\core\var\work\ABS_SQL\manifest.txt"
CONST MANIFEST_FNAME = "C:\Users\Public\Documents\Virtual Machines\VmWareShare\Source\awk\DTCC\manifest.txt"
' CONST DEBUG_FLAG = True
CONST DEBUG_FLAG = true
'
CONST MANIFEST_FILELIST_DELIMITER = ";"
CONST SEQUENCE_FIELD_WIDTH = 8
'
' Regular expression to process a line from the manifest file:
'     Starting at beginning of line, skip 0 or more WHITESPACE chars
'     Capture 1 or more digits                                          (sequence number)
'     Skip 1 or more WHITESPACE chars
'     Capture 1 or more non-WHITESPACE chars                            (file name)
CONST MANIFEST_FILE_REGEX = "^\s*(\d+)\s+(\S+)"
'
' ----------------------------------------------------------------------------
Dim   fso , dict_Manifest , regex_ManifestLine , txtstream_ManifestFile , _
      match_ManifestLine , obj_WorkingDirFldr , obj_File , obj_FilesCollection
'
Dim   str_Line , n_Line , str_ManifestEntrySequenceId , _
      str_ManifestEntryFilename , str_Delimited_Manifest_Filelist , _ 
      str_ManifestFname
' ----------------------------------------------------------------------------
'
'
'  The only NO ERROR condition is if the contents of manifest.txt equals the
'     contents of working directory:
'        If working dir is empty: error
'        No manifest: error,
'        Something on manifest and not in working: error
'        Something in working and not on manifest: error
'     Both need to equal each other.
'
'
'
If FileExists(MANIFEST_FNAME) Then
   '
   If Not FolderExists(WORKING_DIR) Then
      WScript.Echo "Can't find Working Dir '" & WORKING_DIR & "'.  Exit with error."
      WScript.Quit 1
   End If
   '
   '  Read the manifest file and verify every file exists in working dir.
   '  Build a list of every filename delimited by some character to allow
   '  us to verify that every file in the Working Dir is in the Manifest.
   '
   Set fso = CreateObject("Scripting.FileSystemObject")
   Set regex_ManifestLine = GetRegEx(MANIFEST_FILE_REGEX,true,false)
   '
   ' NOTE: Unlike the match script, this dictionary uses the sequence number
   '     from the Manifest as the key, and the filename as the value.
   Set dict_Manifest = CreateObject("Scripting.Dictionary")
   '
   WScript.Echo "Reading Manifest file '" & MANIFEST_FNAME & "'"
   Set txtstream_ManifestFile = fso.OpenTextFile(MANIFEST_FNAME, vbForReading, false, vbTristateUseDefault)
   '
   '
   '
   While Not txtstream_ManifestFile.AtEndOfStream
      str_Line = txtstream_ManifestFile.ReadLine
      n_Line = n_Line + 1
      If DEBUG_FLAG Then WScript.echo "DEBUG :: Manifest line='" & str_Line & "'"
      Set match_ManifestLine = regex_ManifestLine.Execute(str_Line)
      If match_ManifestLine.Count > 0 Then
         str_ManifestEntrySequenceId = Trim(match_ManifestLine(0).SubMatches(0))
         str_ManifestEntryFilename = Trim(match_ManifestLine(0).SubMatches(1))
         '
         If DEBUG_FLAG Then WScript.Echo "DEBUG :: Seq#=" & str_ManifestEntrySequenceId & " ; file=" & str_ManifestEntryFilename
         '
         ' Check for dup filenames by trying to find the current line filename in the delimited filelist.
         If Instr(1,str_Delimited_Manifest_Filelist & MANIFEST_FILELIST_DELIMITER , _
            MANIFEST_FILELIST_DELIMITER & str_ManifestEntryFilename & MANIFEST_FILELIST_DELIMITER,vbTextCompare) > 0 Then
               WScript.Echo "File '" & str_ManifestEntryFilename & _
                  "' repeated in Manifest at line #" & n_Line & ".  Exiting with error."
               WScript.Quit 1
         End If
         '
         ' Check for dup sequence numbers in manifest by seeing if the
         '     manifest filename dictionary already has an entry for the
         '     current line sequence number.
         If dict_Manifest.Exists(str_ManifestEntrySequenceId) Then
            WScript.Echo "Sequence number:" & str_ManifestEntrySequenceId & " for file '" & dict_Manifest.Item(str_ManifestEntrySequenceId) & _
               "' repeated in Manifest at line #" & n_Line & " for file '" & str_ManifestEntryFilename & "'.  Exiting with error."
            WScript.Quit 1
         End If
         '
         ' Make sure the file exists.
         If FileExists(WORKING_DIR & PATHDELIM & str_ManifestEntryFilename) Then
            WScript.Echo "Found File '" & str_ManifestEntryFilename & "' listed in Manifest at line #" & n_Line
         Else
            WScript.Echo "File '" & str_ManifestEntryFilename & "' listed in Manifest '" & MANIFEST_FNAME & "', line #" & n_Line & " not found.  Exiting with error."
            WScript.Quit 1
         End If
         '
         ' If we made it this far without problems, add current line info
         '     to the dictionary and the delimited filelist.
         str_Delimited_Manifest_Filelist = str_Delimited_Manifest_Filelist & MANIFEST_FILELIST_DELIMITER & str_ManifestEntryFilename
         Call dict_Manifest.Add( str_ManifestEntrySequenceId , str_ManifestEntryFilename )
         '
         '
      Else
         ' Blank line
      End If
   Wend
   '
   ' Don't need this stuff anymore.
   txtstream_ManifestFile.Close
   Set txtstream_ManifestFile = Nothing
   Set match_ManifestLine = Nothing
   Set regex_ManifestLine = Nothing
   '
   ' Append a trailing delimiter to the delimited list.
   str_Delimited_Manifest_Filelist = str_Delimited_Manifest_Filelist & MANIFEST_FILELIST_DELIMITER
   '
   If DEBUG_FLAG Then WScript.echo "DEBUG :: Delimited Manifest Filelist = '" & str_Delimited_Manifest_Filelist & "'"
   '
   ' Now check every file in the working directory and verify that it was/is in the Manifest.
   Set obj_WorkingDirFldr = fso.GetFolder(WORKING_DIR)
   Set obj_FilesCollection = obj_WorkingDirFldr.Files
   If DEBUG_FLAG Then WScript.echo "DEBUG :: Found " & obj_FilesCollection.Count & " files in Working dir '" & WORKING_DIR & "'"
   '
   ' Extract just the filename portion of the Manifest path
   str_ManifestFname = LCase(fso.GetFileName(MANIFEST_FNAME))
   If DEBUG_FLAG Then WScript.echo "DEBUG :: Manifest filename='" & str_ManifestFname & "'"
   '
   ' If "manifest.txt" is the only file in the Working Dir then it's an error.
   If obj_FilesCollection.Count = 0 Then
      WScript.Echo "Working Dir is empty.  Exit with error."
      WScript.Quit 1
   ElseIf obj_FilesCollection.Count = 1 Then
      If LCase(FirstItem(obj_FilesCollection).Name) = str_ManifestFname Then
         WScript.Echo "Manifest is the only file in the Working Dir.  Exit with error."
         WScript.Quit 1
      End If
   End If
   '
   ' All files in Working Dir must be in the Manifest.
   For Each obj_File in obj_FilesCollection
      If LCase(obj_File.name) <> str_ManifestFname Then
         ' Use case-insensitive comparison on filename because Windows is case-insensitive on filename.
         If Instr(1,str_Delimited_Manifest_Filelist , MANIFEST_FILELIST_DELIMITER & obj_File.Name & MANIFEST_FILELIST_DELIMITER, vbTextCompare) > 0 Then
            If DEBUG_FLAG Then WScript.Echo "File '" & obj_File.Name & "' is present in Manifest."
         Else
            WScript.Echo "Can't find file '" & obj_File.Name & "' in Manifest.  Exit with error"
            WScript.Quit 1
         End If
      End If
   Next
'
Else
   WScript.Echo "Manifest file '" & MANIFEST_FNAME & "' not found.  Exiting with error."
   WScript.Quit 1
End If
'
' Cleanup
Set obj_File=Nothing
Set obj_FilesCollection=Nothing
Set obj_WorkingDirFldr=Nothing
Set fso=Nothing
'
'
' If we made it this far then life is good.
WScript.Quit 0
'
' ----------------------------------------------------------------------------
' ----------------------------------------------------------------------------
' Return the first item in the collection
Function FirstItem(obj)
   For Each FirstItem In obj
      Exit For
   Next
End Function
' ----------------------------------------------------------------------------
' Return TRUE if specified File exists.
Function FileExists(strFname)
   Dim fso
   Set fso = CreateObject("Scripting.FileSystemObject")
   FileExists = fso.FileExists(strFname)
   Set fso = Nothing
End Function
' ----------------------------------------------------------------------------
' Return TRUE if specified Dir exists.
Function FolderExists(strDirname)
   Dim fso
   Set fso = CreateObject("Scripting.FileSystemObject")
   FolderExists = fso.FolderExists(strDirname)
   Set fso = Nothing
End Function
' ----------------------------------------------------------------------------
' Create & return a Regular Expression object given the pattern and flags.
'  Within the body of a VBScript function we can treat the function name
'     as a declared variable.
Function GetRegEx(str_Pattern , bool_IgnoreCase , bool_Global)
   Set GetRegEx = New RegExp
   '
   GetRegEx.Pattern = str_Pattern
   GetRegEx.IgnoreCase = bool_IgnoreCase
   GetRegEx.Global = bool_Global
End Function
' ----------------------------------------------------------------------------